/*
 *------------------------------------------------------------------------------
 * @File      :    ov8858_mipi.c
 * @Date      :    2021-3-20
 * @Author    :    lomboswer <lomboswer@lombotech.com>
 * @Brief     :    Source file for MDP(Media Development Platform).
 *
 * Copyright (C) 2020-2021, LomboTech Co.Ltd. All rights reserved.
 *------------------------------------------------------------------------------
 */
#include "ei_comm_camera.h"
#include "camera_usr.h"

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */

#define SNS_ID 8858
#define SNS_NAME  "ov8858_mipi"
#define DEV_TYPE MCSI

static SNS_STATE_S g_sastSns[VISS_MAX_DEV_NUM];

static const SNS_REG_S s_aInitSet[] = {
	{0x0100,0x00},
	{0x0302,0x0f},//0f
	{0x0303,0x00},
	{0x0304,0x03},
	{0x030d,0x0f},//0f
	{0x030e,0x00},
	{0x030f,0x04},
	{0x0312,0x01},
	{0x031e,0x0c},
	{0x3600,0x00},
	{0x3601,0x00},
	{0x3602,0x00},
	{0x3603,0x00},
	{0x3604,0x22},
	{0x3605,0x20},
	{0x3606,0x00},
	{0x3607,0x20},
	{0x3608,0x11},
	{0x3609,0x28},
	{0x360a,0x00},
	{0x360b,0x05},
	{0x360c,0xd4},
	{0x360d,0x40},
	{0x360e,0x0c},
	{0x360f,0x20},
	{0x3610,0x07},
	{0x3611,0x20},
	{0x3612,0x88},
	{0x3613,0x80},
	{0x3614,0x58},
	{0x3615,0x00},
	{0x3616,0x4a},
	{0x3617,0x40},
	{0x3618,0x5a},
	{0x3619,0x70},
	{0x361a,0x99},
	{0x361b,0x0a},
	{0x361c,0x07},
	{0x361d,0x00},
	{0x361e,0x00},
	{0x361f,0x00},
	{0x3638,0xff},
	{0x3633,0x0f},
	{0x3634,0x0f},
	{0x3635,0x0f},
	{0x3636,0x12},
	{0x3645,0x13},
	{0x3646,0x83},
	{0x364a,0x07},
	{0x3015,0x01},
	{0x3018,0x72},// 4 lanes
	//{0x3018,0x32},// 2 lanes
	{0x3020,0x93},
	{0x3022,0x01},
	{0x3031,0x0a},// ; MIPI 10-bit mode
	//{0x3031,0x08},// ; MIPI 8-bit mode
	{0x3034,0x00},
	{0x3106,0x01},
	{0x3305,0xf1},
	{0x3308,0x00},
	{0x3309,0x28},
	{0x330a,0x00},
	{0x330b,0x20},
	{0x330c,0x00},
	{0x330d,0x00},
	{0x330e,0x00},
	{0x330f,0x40},
	{0x3307,0x04},
	{0x3500,0x00},
	{0x3501,0x4d},
	{0x3502,0x40},
	{0x3503,0x80},
	{0x3505,0x80},
	{0x3508,0x04},
	{0x3509,0x00},
	{0x350c,0x00},
	{0x350d,0x80},
	{0x3510,0x00},
	{0x3511,0x02},
	{0x3512,0x00},
	{0x3700,0x30},
	{0x3701,0x18},
	{0x3702,0x50},
	{0x3703,0x32},
	{0x3704,0x28},
	{0x3705,0x00},
	{0x3706,0x82},
	{0x3707,0x08},
	{0x3708,0x48},
	{0x3709,0x66},
	{0x370a,0x01},
	{0x370b,0x82},
	{0x370c,0x07},
	{0x3718,0x14},
	{0x3719,0x31},
	{0x3712,0x44},
	{0x3714,0x24},
	{0x371e,0x31},
	{0x371f,0x7f},
	{0x3720,0x0a},
	{0x3721,0x0a},
	{0x3724,0x0c},
	{0x3725,0x02},
	{0x3726,0x0c},
	{0x3728,0x0a},
	{0x3729,0x03},
	{0x372a,0x06},
	{0x372b,0xa6},
	{0x372c,0xa6},
	{0x372d,0xa6},
	{0x372e,0x0c},
	{0x372f,0x20},
	{0x3730,0x02},
	{0x3731,0x0c},
	{0x3732,0x28},
	{0x3733,0x10},
	{0x3734,0x40},
	{0x3736,0x30},
	{0x373a,0x0a},
	{0x373b,0x0b},
	{0x373c,0x14},
	{0x373e,0x06},
	{0x3750,0x0a},
	{0x3751,0x0e},
	{0x3755,0x10},
	{0x3758,0x00},
	{0x3759,0x4c},
	{0x375a,0x0c},
	{0x375b,0x26},
	{0x375c,0x20},
	{0x375d,0x04},
	{0x375e,0x00},
	{0x375f,0x28},
	{0x3768,0x22},
	{0x3769,0x44},
	{0x376a,0x44},
	{0x3761,0x00},
	{0x3762,0x00},
	{0x3763,0x00},
	{0x3766,0xff},
	{0x376b,0x00},
	{0x3772,0x46},
	{0x3773,0x04},
	{0x3774,0x2c},
	{0x3775,0x13},
	{0x3776,0x08},
	{0x3777,0x00},
	{0x3778,0x17},
	{0x37a0,0x88},
	{0x37a1,0x7a},
	{0x37a2,0x7a},
	{0x37a3,0x00},
	{0x37a4,0x00},
	{0x37a5,0x00},
	{0x37a6,0x00},
	{0x37a7,0x88},
	{0x37a8,0x98},
	{0x37a9,0x98},
	{0x3760,0x00},
	{0x376f,0x01},
	{0x37aa,0x88},
	{0x37ab,0x5c},
	{0x37ac,0x5c},
	{0x37ad,0x55},
	{0x37ae,0x19},
	{0x37af,0x19},
	{0x37b0,0x00},
	{0x37b1,0x00},
	{0x37b2,0x00},
	{0x37b3,0x84},
	{0x37b4,0x84},
	{0x37b5,0x60},
	{0x37b6,0x00},
	{0x37b7,0x00},
	{0x37b8,0x00},
	{0x37b9,0xff},
	{0x3800,0x00},
	{0x3801,0x0c},
	{0x3802,0x00},
	{0x3803,0x0c},
	{0x3804,0x0c},
	{0x3805,0xd3},
	{0x3806,0x09},
	{0x3807,0xa3},
	{0x3808,0x06},
	{0x3809,0x60},
	{0x380a,0x04},
	{0x380b,0xc8},
	{0x380c,0x07},
	{0x380d,0x88},
	{0x380e,0x04},
	{0x380f,0xdc},
	{0x3810,0x00},
	{0x3811,0x04},
	{0x3813,0x02},
	{0x3814,0x03},
	{0x3815,0x01},
	{0x3820,0x00},
	{0x3821,0x67},
	{0x382a,0x03},
	{0x382b,0x01},
	{0x3830,0x08},
	{0x3836,0x02},
	{0x3837,0x18},
	{0x3841,0xff},
	{0x3846,0x48},
	{0x3d85,0x16},
	{0x3d8c,0x73},
	{0x3d8d,0xde},
	{0x3f08,0x10},
	{0x3f0a,0x00},
	{0x4000,0xf1},
	{0x4001,0x10},
	{0x4005,0x10},
	{0x4002,0x27},
	{0x4009,0x81},
	{0x400b,0x0c},
	{0x4011,0x20},
	{0x401b,0x00},
	{0x401d,0x00},
	{0x4020,0x00},
	{0x4021,0x04},
	{0x4022,0x06},
	{0x4023,0x00},
	{0x4024,0x0f},
	{0x4025,0x2a},
	{0x4026,0x0f},
	{0x4027,0x2b},
	{0x4028,0x00},
	{0x4029,0x02},
	{0x402a,0x04},
	{0x402b,0x04},
	{0x402c,0x00},
	{0x402d,0x02},
	{0x402e,0x04},
	{0x402f,0x04},
	{0x401f,0x00},
	{0x4034,0x3f},
	{0x403d,0x04},
	{0x4300,0xff},
	{0x4301,0x00},
	{0x4302,0x0f},
	{0x4316,0x00},
	{0x4500,0x58},
	{0x4503,0x18},
	{0x4600,0x00},
	{0x4601,0xcb},
	{0x4800,0x4c},// gate clock lane when there is no packet transmit
	//bit5 = 0 is clock lane freerun mode
	{0x481f,0x32},
	{0x4837,0x16},
	{0x4850,0x10},
	{0x4851,0x32},
	{0x4b00,0x2a},
	{0x4b0d,0x00},
	{0x4d00,0x04},
	{0x4d01,0x18},
	{0x4d02,0xc3},
	{0x4d03,0xff},
	{0x4d04,0xff},
	{0x4d05,0xff},
	{0x5000,0x7e},
	{0x5001,0x01},
	{0x5002,0x08},
	{0x5003,0x20},
	{0x5046,0x12},
	{0x5780,0x3e},
	{0x5781,0x0f},
	{0x5782,0x44},
	{0x5783,0x02},
	{0x5784,0x01},
	{0x5785,0x00},
	{0x5786,0x00},
	{0x5787,0x04},
	{0x5788,0x02},
	{0x5789,0x0f},
	{0x578a,0xfd},
	{0x578b,0xf5},
	{0x578c,0xf5},
	{0x578d,0x03},
	{0x578e,0x08},
	{0x578f,0x0c},
	{0x5790,0x08},
	{0x5791,0x04},
	{0x5792,0x00},
	{0x5793,0x52},
	{0x5794,0xa3},
	{0x5871,0x0d},
	{0x5870,0x18},
	{0x586e,0x10},
	{0x586f,0x08},
	{0x58f8,0x3d},
	{0x5901,0x00},
	{0x5b00,0x02},
	{0x5b01,0x10},
	{0x5b02,0x03},
	{0x5b03,0xcf},
	{0x5b05,0x6c},
	{0x5e00,0x00},
	{0x5e01,0x41},
	{0x382d,0x7f},
	{0x4825,0x3a},
	{0x4826,0x40},
	{0x4808,0x25},
	{0x3763,0x18},
	{0x3768,0xcc},
	{0x470b,0x28},
	{0x4202,0x00},
	{0x400d,0x10},
	{0x4040,0x07},
	{0x403e,0x08},
	{0x4041,0xc6},
	{0x3007,0x80},
	{0x400a,0x01},
	//{0x5e00, 0x80},//color bar mode
};

static const SNS_REG_S s_a8MSet[] = {
	//@@ Capture setting
	//100 99 3264 2448 ; Resolution
	//{0x0100,0x00}

	{0x0302,0x1e},//1e=720Mbps,  2a=1008Mbps 28=960Mbps
	/*
	default is 0x0F(15fps), 0x1e(30fps) will increase frame rate
	*/
	{0x030d,0x1e},
	{0x3769,0x44},
	{0x376a,0x44},
	{0x3808,0x0c},
	{0x3809,0xc0},
	{0x380a,0x09},
	{0x380b,0x90},
	{0x380c,0x07},
	{0x380d,0x94},
	{0x380e,0x09},
	{0x380f,0xaa},
	{0x3814,0x01},
	{0x3821,0x40},
	{0x382a,0x01},
	{0x302b,0x01},
	{0x3830,0x06},
	{0x3836,0x01},
	{0x4000,0xf1},
	{0x4001,0x00},
	{0x4022,0x0c},
	{0x4023,0x60},
	{0x4025,0x36},
	{0x4027,0x37},
	{0x402a,0x04},
	{0x402b,0x08},
	{0x402e,0x04},
	{0x402f,0x08},
	{0x4600,0x01},
	{0x4601,0x97},
	{0x382d,0xff},
	{0x5901,0x00},
	//i2c_write_byte(0x5E00,0x80);//standard color
	//{0x0100,0x01}
};

static CAMERA_POWER_ACT_S s_stPowerUpAct[] = {
    {SNS_RESET, SNS_DOWN},
    {SNS_DELAY, 1},
    {SNS_PWDN, SNS_DOWN},
    {SNS_DELAY, 10},
    {SNS_PWDN, SNS_UP},
    {SNS_DELAY, 1},
    {SNS_RESET, SNS_UP},
    {SNS_DELAY, 10},
};

static CAMERA_POWER_ACT_S s_sPowerDownAct[] = {
    {SNS_PWDN, SNS_DOWN},
    {SNS_DELAY, 5},
    {SNS_RESET, SNS_DOWN},
    {SNS_DELAY, 5},
};

static SNS_TYPE_ATTR_S s_astSnsAttr[] = {
    {
        .enSnsType                  = OV8858_MIPI_3264_2448_30FPS_RAW10,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_10BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_BGGR,
        .stSize                     = {3264, 2448},
        .u32ModuleClk               = 297000000,
        .u32Mclock                  = 24000000,
        .enWorkMode                 = VISS_WORK_MODE_1Chn,

        .u32FrameRate                = 30,
        .astRegCfgs[0].pstRegs      = s_aInitSet,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aInitSet),
        .astRegCfgs[1].pstRegs      = s_a8MSet,
        .astRegCfgs[1].u32RegsCnt   = ARRAY_SIZE(s_a8MSet),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 720000000,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_4Lane,
    },
};

static int CAMERA_SetI2cInfo(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    if (pstSnsState->stI2cInfo.fd > 0) {
        return EI_SUCCESS;
    }

    pstSnsState->stI2cInfo.u8RegBits = 16;
    pstSnsState->stI2cInfo.u8ValBits = 8;
    pstSnsState->stI2cInfo.u16I2cBusNum = 4;
    pstSnsState->stI2cInfo.u16I2cDevAddr = 0x36;
    pstSnsState->pcName = SNS_NAME;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_Detect(VISS_DEV VissDev)
{
    EI_U8 u8Tmp[2];
    EI_S32 s32Ret = EI_SUCCESS;
    EI_U16 u16Id;
    SNS_STATE_S *pstSnsState = EI_NULL;
    I2C_INFO_S *pstI2cInfo = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);

    pstI2cInfo = &pstSnsState->stI2cInfo;

    CAMERA_CHECK_POINTER(pstI2cInfo->pfnReadReg);
    s32Ret = pstI2cInfo->pfnReadReg(pstSnsState, 0x300b, &u8Tmp[0]);
    if (s32Ret != 0) {
        PRT_VISS_ERR("tmp[0]=%x\n", u8Tmp[0]);
        return s32Ret;
    }
    s32Ret = pstI2cInfo->pfnReadReg(pstSnsState, 0x300c, &u8Tmp[1]);
    if (s32Ret != 0) {
        PRT_VISS_ERR("tmp[0]=%x,tmp[1]=%x\n", u8Tmp[0], u8Tmp[1]);
        return s32Ret;
    }
    u16Id = (u8Tmp[0] << 8) | u8Tmp[1];
    PRT_VISS_INFO("%s id: 0x%04x\n", SNS_NAME, u16Id);

    if (u16Id != 0x8858) {
        PRT_VISS_ERR("ID wrong! (0x%04x != 0x8858)\n", u16Id);
        return EI_FAILURE;
    }

    return EI_SUCCESS;
}

static EI_S32 CAMERA_Stream(VISS_DEV dev, EI_BOOL bOn)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret = EI_SUCCESS;
    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);
    PRT_VISS_ERR("%s CAMERA_Stream-------%d\n", SNS_NAME, bOn);

    if (bOn) {
        s32Ret = pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x0100, 0x01);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("CAMERA_Stream---------%d\n", bOn);
        }
    } else {
        s32Ret = pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x0100, 0x00);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("CAMERA_Stream---------%d\n", bOn);
        }
    }
    return s32Ret;

}

/* The following functions can be modified as needed */

static int CAMERA_I2cInit(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    int ret = EI_SUCCESS;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    ret = CAMERA_SetI2cInfo(dev);
    CAMERA_CHECK_SUCCESS(ret);

    ret = CAMERA_I2C_Reg_Ops(&pstSnsState->stI2cInfo);
    CAMERA_CHECK_SUCCESS(ret);

    return EI_SUCCESS;
}

static int CAMERA_I2cExit(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_PowerUp(VISS_DEV VissDev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);

    CAMERA_SensorPowerUp(VissDev, pstSnsState);

    return 0;
}

static EI_S32 CAMERA_PowerDown(VISS_DEV VissDev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);

    CAMERA_SensorPowerDown(VissDev, pstSnsState);

    return 0;
}

static EI_S32 CAMERA_Init(VISS_DEV dev)
{
    EI_U32 j;
    const SNS_TYPE_ATTR_S *pstSnsType;
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    pstSnsType = pstSnsState->pstSnsAttr;
    for (j = 0; j < MAX_COF; j++) {
        s32Ret = pstSnsState->stI2cInfo.pfnwriteRegList(pstSnsState,
                pstSnsType->astRegCfgs[j].pstRegs, pstSnsType->astRegCfgs[j].u32RegsCnt);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("%s writeRegList err", SNS_NAME);
            return s32Ret;
        }
    }

    PRT_VISS_INFO("%s writeRegList success", SNS_NAME);

    return s32Ret;
}

static void CAMERA_Exit(VISS_DEV dev)
{
    CAMERA_I2cExit(dev);

    return;
}

static EI_S32 CAMERA_SetImageMode(VISS_DEV dev, SNS_TYPE_E enSnsType)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    pstSnsState->enSnsType = enSnsType;
    pstSnsState->bSyncInit = EI_FALSE;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_EnumSnstype(VISS_DEV VissDev, EI_U32 u32Index, SNS_TYPE_E *peSnstype)
{
    const SNS_TYPE_ATTR_S *pstSnsType;

    if (u32Index >= ARRAY_SIZE(s_astSnsAttr))
        return EN_ERR_NO_FOUND;

    pstSnsType = &s_astSnsAttr[u32Index];

    *peSnstype = pstSnsType->enSnsType;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_InitSensorExpFunction(SENSOR_EXP_FUNC_S *pstSensorExpFunc)
{
    CAMERA_CHECK_POINTER(pstSensorExpFunc);

    memset(pstSensorExpFunc, 0, sizeof(SENSOR_EXP_FUNC_S));

    pstSensorExpFunc->pfnSensorPowerUp  = CAMERA_PowerUp;
    pstSensorExpFunc->pfnSensorPowerDown = CAMERA_PowerDown;
    pstSensorExpFunc->pfnSensorDetect   = CAMERA_Detect;
    pstSensorExpFunc->pfnSensorInit     = CAMERA_Init;
    pstSensorExpFunc->pfnSensorStream   = CAMERA_Stream;
    pstSensorExpFunc->pfnSensorExit     = CAMERA_Exit;
    pstSensorExpFunc->pfnSensorSetImageMode   = CAMERA_SetImageMode;
    pstSensorExpFunc->pfnSensorEnumSnstype   = CAMERA_EnumSnstype;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_GetAeDefault(ISP_DEV dev, AE_SENSOR_DEFAULT_S *pstAeSnsDft)
{
    CAMERA_CHECK_POINTER(pstAeSnsDft);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_SetFps(ISP_DEV dev, EI_FLOAT f32Fps, AE_SENSOR_DEFAULT_S *pstAeSnsDft)
{
    CAMERA_CHECK_POINTER(pstAeSnsDft);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_SetExpTime(ISP_DEV dev, EI_FLOAT *afIntTime)
{
    return EI_SUCCESS;
}

static EI_S32 CAMERA_SetGain(ISP_DEV dev, EI_FLOAT fGain)
{
    return EI_SUCCESS;
}

static EI_S32 CAMERA_InitAeExpFunction(AE_SENSOR_EXP_FUNC_S *pstExpFuncs)
{
    CAMERA_CHECK_POINTER(pstExpFuncs);

    memset(pstExpFuncs, 0, sizeof(AE_SENSOR_EXP_FUNC_S));

    pstExpFuncs->pfnGetAeDefault    = CAMERA_GetAeDefault;
    pstExpFuncs->pfnSetFps          = CAMERA_SetFps;
    pstExpFuncs->pfnSetExpTime      = CAMERA_SetExpTime;
    pstExpFuncs->pfnSetGain         = CAMERA_SetGain;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_GetAwbDefault(ISP_DEV dev, AWB_SENSOR_DEFAULT_S *pstAwbSnsDft)
{
    CAMERA_CHECK_POINTER(pstAwbSnsDft);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_InitAwbExpFunction(AWB_SENSOR_EXP_FUNC_S *pstExpFuncs)
{
    CAMERA_CHECK_POINTER(pstExpFuncs);

    memset(pstExpFuncs, 0, sizeof(AWB_SENSOR_EXP_FUNC_S));
    pstExpFuncs->pfnGetAwbDefault = CAMERA_GetAwbDefault;

    return EI_SUCCESS;
}

/****************************************************************************
 * callback structure                                                       *
 ****************************************************************************/

static EI_S32 CAMERA_CtxInit(VISS_DEV dev)
{
    SNS_STATE_S *pastSnsStateCtx = EI_NULL;

    SNS_GET_CTX(dev, pastSnsStateCtx);

    CAMERA_CHECK_POINTER(pastSnsStateCtx);

    memset(pastSnsStateCtx, 0, sizeof(SNS_STATE_S));

    pastSnsStateCtx->pstPowerUpAct      = s_stPowerUpAct;
    pastSnsStateCtx->pstPowerDownAct    = s_sPowerDownAct;
    pastSnsStateCtx->u8PwrUpActs        = ARRAY_SIZE(s_stPowerUpAct);
    pastSnsStateCtx->u8PwrDnActs        = ARRAY_SIZE(s_sPowerDownAct);

    return EI_SUCCESS;
}

static EI_VOID CAMERA_CtxExit(VISS_DEV dev)
{
    return ;
}

static EI_S32 CAMERA_RegisterVissCallback(VISS_DEV dev, SNS_TYPE_E enType)
{
    EI_S32 s32Ret;
    SENSOR_S stSns = {0};
    EI_U32 i;
    SNS_STATE_S *pstSnsState = EI_NULL;

    s32Ret = CAMERA_CtxInit(dev);
    if (EI_SUCCESS != s32Ret) {
        return EI_FAILURE;
    }

    SNS_GET_CTX(dev, pstSnsState);

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsState->pstSnsAttr = &s_astSnsAttr[i];
            break;
        }
    }

    pstSnsState->enSnsType = enType;
    pstSnsState->Dev = dev;

    if (i >= ARRAY_SIZE(s_astSnsAttr)) {
        PRT_VISS_ERR("%s does not support this chn configuration", SNS_NAME);
        return EI_FAILURE;
    }

    s32Ret = CAMERA_I2cInit(dev);
    if (EI_SUCCESS != s32Ret) {
        return EI_FAILURE;
    }

    stSns.stSnsAttrInfo.eSensorId = SNS_ID;
    stSns.stSnsAttrInfo.enDevType = DEV_TYPE;
    stSns.stSnsAttrInfo.pstSns = pstSnsState;

    s32Ret  = CAMERA_InitSensorExpFunction(&stSns.stSnsAttrInfo.stSnsExp);
    s32Ret |= VISS_SensorRegCallBack(dev, &stSns);
    if (EI_SUCCESS != s32Ret) {
        PRT_VISS_ERR("%s sensor register callback function failed!\n", SNS_NAME);
        return s32Ret;
    }

    s32Ret = CAMERA_OpenI2c(pstSnsState);
    CAMERA_CHECK_SUCCESS(s32Ret);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_UnregisterVissCallback(VISS_DEV dev)
{
    EI_S32 s32Ret;
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);

    s32Ret = CAMERA_ExitI2c(pstSnsState);
    CAMERA_CHECK_SUCCESS(s32Ret);

    s32Ret = VISS_SensorUnRegCallBack(dev, SNS_ID);
    if (EI_SUCCESS != s32Ret) {
        PRT_VISS_ERR("%s sensor unregister callback function failed!\n", SNS_NAME);
        return s32Ret;
    }

    CAMERA_CtxExit(dev);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_RegisterIspCallback(VISS_DEV Dev, ISP_DEV dev, ISP_3ALIB_S *pstAeLib, ISP_3ALIB_S *pstAwbLib)
{
    EI_S32 s32Ret;
    AE_SENSOR_REGISTER_S  stAeRegister;
    AWB_SENSOR_REGISTER_S stAwbRegister;

    CAMERA_CHECK_POINTER(pstAeLib);
    CAMERA_CHECK_POINTER(pstAwbLib);

    stAeRegister.SnsId = SNS_ID;
    stAwbRegister.SnsId = SNS_ID;

    s32Ret  = CAMERA_InitAeExpFunction(&stAeRegister.stSnsExp);
    s32Ret |= EI_MI_AE_SensorRegCallBack(dev, pstAeLib, &stAeRegister);

    if (EI_SUCCESS != s32Ret) {
        EI_TRACE_ISP(EI_DBG_ERR, "%s register callback function to ae lib failed!\n", SNS_NAME);
        return s32Ret;
    }

    s32Ret  = CAMERA_InitAwbExpFunction(&stAwbRegister.stSnsExp);
    s32Ret |= EI_MI_AWB_SensorRegCallBack(dev, pstAwbLib, &stAwbRegister);

    if (EI_SUCCESS != s32Ret) {
        EI_TRACE_ISP(EI_DBG_ERR, "%s register callback function to awb lib failed!\n", SNS_NAME);
        return s32Ret;
    }

    return EI_SUCCESS;
}

static EI_S32 CAMERA_UnregisterIspCallback(ISP_DEV dev, ISP_3ALIB_S *pstAeLib, ISP_3ALIB_S *pstAwbLib)
{
    EI_S32 s32Ret;

    CAMERA_CHECK_POINTER(pstAeLib);
    CAMERA_CHECK_POINTER(pstAwbLib);

    s32Ret = EI_MI_AE_SensorUnRegCallBack(dev, pstAeLib, SNS_ID);
    if (EI_SUCCESS != s32Ret) {
        EI_TRACE_ISP(EI_DBG_ERR, "%s unregister callback function to ae lib failed!\n", SNS_NAME);
        return s32Ret;
    }

    s32Ret = EI_MI_AWB_SensorUnRegCallBack(dev, pstAwbLib, SNS_ID);
    if (EI_SUCCESS != s32Ret) {
        EI_TRACE_ISP(EI_DBG_ERR, "%s unregister callback function to awb lib failed!\n", SNS_NAME);
        return s32Ret;
    }

    return EI_SUCCESS;
}

static EI_S32 CAMERA_GetVissDevAttrBySns(SNS_TYPE_E enType,
    VISS_DEV_ATTR_S *pstVissDevAttr)
{
    EI_U32 i;
    const SNS_TYPE_ATTR_S *pstSnsType;

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsType = &s_astSnsAttr[i];
            pstVissDevAttr->stSize          = pstSnsType->stSize;
            pstVissDevAttr->enWorkMode      = pstSnsType->enWorkMode;
            pstVissDevAttr->mClock          = pstSnsType->u32Mclock;
            pstVissDevAttr->enPixelFormat   = pstSnsType->enPixelFormat;
            pstVissDevAttr->enWdrMode       = pstSnsType->enWdrMode;
            pstVissDevAttr->enIspWdrMode    = pstSnsType->enIspWdrMode;
            pstVissDevAttr->enRgbSeq        = pstSnsType->enRgbSeq;
            pstVissDevAttr->u32ModuleClk    = pstSnsType->u32ModuleClk;
            pstVissDevAttr->u32Fps          = pstSnsType->u32FrameRate;
            pstVissDevAttr->u32IspClk       = pstSnsType->u32IspClk;
            pstVissDevAttr->u32IppuClk      = pstSnsType->u32IppuClk;
            pstVissDevAttr->pcSnsName       = SNS_NAME;
            pstVissDevAttr->stDevCfg        = pstSnsType->stDevCfg;
            return EI_SUCCESS;
        }
    }

    PRT_VISS_ERR("%s does not support this dev configuration", SNS_NAME);

    return EI_FAILURE;
}

static EI_S32 CAMERA_GetVissChnAttrBySns(SNS_TYPE_E enType,
    VISS_CHN_ATTR_S *pstVissChnAttr)
{
    EI_U32 i;
    const SNS_TYPE_ATTR_S *pstSnsType;

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsType = &s_astSnsAttr[i];
            pstVissChnAttr->stSize           = pstSnsType->stSize;
            pstVissChnAttr->enPixelFormat    = pstSnsType->enPixelFormat;
            pstVissChnAttr->stFrameRate.s32SrcFrameRate      = pstSnsType->u32FrameRate;
            return EI_SUCCESS;
        }
    }

    PRT_VISS_ERR("%s does not support this chn configuration", SNS_NAME);

    return EI_FAILURE;

}

CAMERA_OBJ_S stCameraOv8858mipiObj = {
    .pfnRegisterVissCallback    = CAMERA_RegisterVissCallback,
    .pfnUnRegisterVissCallback  = CAMERA_UnregisterVissCallback,
    .pfnRegisterIspCallback     = CAMERA_RegisterIspCallback,
    .pfnUnRegisterIspCallback   = CAMERA_UnregisterIspCallback,
    .pfnGetVissDevAttrBySns     = CAMERA_GetVissDevAttrBySns,
    .pfnGetVissChnAttrBySns     = CAMERA_GetVissChnAttrBySns,
};

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

